package com.eregg.learn.netty.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

public class NettyServer {

    public static void main(String[] args) {

        /**
         * 两个NioEventLoopGroup，这两个对象可以看做是传统IO编程模型的两大线程组，
         * bossGroup表示监听端口，accept 新连接的线程组，
         * workerGroup表示处理每一条连接的数据读写的线程组
         */

        //ServerBootstrap，这个类将引导我们进行服务端的启动工作
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //boss 对应 IOServer.java 中的接受新连接线程，主要负责创建新连接
        NioEventLoopGroup boss = new NioEventLoopGroup();
        //worker 对应 IOServer.java 中的负责读取数据的线程，主要用于读取数据以及业务逻辑处理
        NioEventLoopGroup worker = new NioEventLoopGroup();

        serverBootstrap
                //1. 指定线程模型
                .group(boss, worker)
                //2. 指定IO模型
                .channel(NioServerSocketChannel.class)
                //3. 指定处理逻辑
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        nioSocketChannel.pipeline().addLast(new FirstServerHandler());
                        //nioSocketChannel.pipeline().addLast(new StringDecoder());
//                        nioSocketChannel.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
//                            @Override
//                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
//                                System.out.println(s);
//                            }
//                        });
                    }
                });

        ChannelFuture channelFuture = bind(serverBootstrap, 8000);

    }

    /**
     * 轮训绑定端口，直至成功
     * @param serverBootstrap
     * @param port
     * @return
     */
    private static ChannelFuture bind(ServerBootstrap serverBootstrap, int port){
        return serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                if (future.isSuccess()) {
                    System.out.println(String.format("端口[%s]绑定成功", port));
                } else {
                    System.out.println(String.format("端口[%s]绑定失败", port));
                    bind(serverBootstrap, port+1);
                }
            }
        });
    }
}
